package proj2501.simple_module;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import proj2501.image_viewer.P013ImageViewer;

public class HomePanel extends JPanel {
	private MyTree tree;
	
	public HomePanel() {
		setLayout(new BorderLayout());
		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
		splitPane.setResizeWeight(0.5);
		JScrollPane leftScrollPane = new JScrollPane();
		tree = new MyTree();
		leftScrollPane.setViewportView(tree);
		
		JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		JButton startButton = new StartButton();
		buttonsPanel.add(startButton);
		
		splitPane.setLeftComponent(leftScrollPane);
		splitPane.setRightComponent(buttonsPanel);
//		add(startButton);
		add(splitPane);
	}
	
	static Object getNewInstance(Class<?> clazz) {
		Constructor<?> constructor;
		try {
			constructor = clazz.getConstructor();
		} catch (NoSuchMethodException e) {
			throw new RuntimeException(e);
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		}
		Object object;
		try {
			object = constructor.newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
		return object;
	}
	
	private class MyTree extends JTree {
		public MyTree() {
			addMouseListener(new MouseAdapter() {
				@Override
				public void mouseClicked(MouseEvent e) {
					super.mouseClicked(e);
					if (e.getClickCount() == 2) {
						TreePath path = getPathForLocation(e.getX(), e.getY());
						if (path != null) {
							System.out.println("Clicked Path: " + path);
							Object object = path.getLastPathComponent();
							System.out.println("Clicked Object: "+object);
							if (object instanceof LeafNode) {
								LeafNode node = (LeafNode) object;
								node.start();
							}
						} else {
							System.out.println("No TreePath was double-clicked.");
						}
					}
				}
			});
			DefaultTreeModel model = new DefaultTreeModel(null);
			
			GroupNode root = new GroupNode("root");
			
			GroupNode a2013_11_06 = new GroupNode("2013-11-06");
			PanelNode bouncingBalls = new PanelNode(P001BouncingBalls.class);
			a2013_11_06.add(bouncingBalls);
			PanelNode snake = new PanelNode(P002Snake.class);
			a2013_11_06.add(snake);
			FrameNode googleSitesFormatter = new FrameNode(P003GoogleSitesFormatter.class);
			a2013_11_06.add(googleSitesFormatter);
			ConsoleOutputNode io = new ConsoleOutputNode(P004IO.class);
			a2013_11_06.add(io);
			FrameNode md5 = new FrameNode(P005MD5.class);
			a2013_11_06.add(md5);
			ConsoleOutputNode xml = new ConsoleOutputNode(P006XML.class);
			a2013_11_06.add(xml);
			PanelNode netLogo = new PanelNode(P007NetLogo.class);
			a2013_11_06.add(netLogo);
			PanelNode puzzle15 = new PanelNode(P008Puzzle15.class);
			a2013_11_06.add(puzzle15);
			root.add(a2013_11_06);
			ConsoleOutputNode jaxb = new ConsoleOutputNode(P009JAXB.class);
			a2013_11_06.add(jaxb);
			PanelNode image = new PanelNode(P010Image.class);
			a2013_11_06.add(image);
			PanelNode sound = new PanelNode(P011Sound.class);
			a2013_11_06.add(sound);
			ConsoleOutputNode rhino = new ConsoleOutputNode(P012Rhino.class);
			a2013_11_06.add(rhino);
			final FrameNode imageViewer = new FrameNode(P013ImageViewer.class);
			a2013_11_06.add(imageViewer);
			PanelNode layout = new PanelNode(P014Layout.class);
			a2013_11_06.add(layout);
			PanelNode component = new PanelNode(P015Component.class);
			a2013_11_06.add(component);
			
			// debug
//			xml.start();
//			System.exit(0);
//			SwingUtilities.invokeLater(new Runnable() {
//				public void run() {
//					imageViewer.start();
//				}
//			});
			
			model.setRoot(root);
			setModel(model);
//			setPreferredSize(new Dimension(200, tree.getPreferredSize().height));
		}
		private class GroupNode extends DefaultMutableTreeNode {
			public GroupNode(Object object) {
				setUserObject(object);
			}
		}
		private abstract class LeafNode extends DefaultMutableTreeNode {
			public void start() {}
		}
		private class PanelNode extends LeafNode {
			public Class<? extends JPanel> clazz;
			public PanelNode(Class<? extends JPanel> clazz) {
				this.clazz = clazz;
				setUserObject(clazz.getSimpleName());
			}
			@Override
			public void start() {
				System.out.println("Starting JPanel: " + clazz.getName());
				super.start();
				JPanel panel = (JPanel) getNewInstance(clazz);
				Container parent = HomePanel.this.getParent();
				parent.remove(HomePanel.this);
				parent.add(panel);
				parent.validate();
				panel.requestFocusInWindow();
			}
		}
		
		private class FrameNode extends LeafNode {
			public Class<? extends JFrame> clazz;
			public FrameNode(Class<? extends JFrame> clazz) {
				this.clazz = clazz;
				setUserObject(clazz.getSimpleName());
			}
			@Override
			public void start() {
				System.out.println("Starting JFrame: " + clazz.getName());
				super.start();
				getNewInstance(clazz);
			}
		}

		private class ConsoleOutputNode extends LeafNode {
			public Class<?> clazz;
			public ConsoleOutputNode(Class<?> clazz) {
				this.clazz = clazz;
				setUserObject(clazz.getSimpleName());
			}
			@Override
			public void start() {
				System.out.println("Starting program module: " + clazz.getName());
				super.start();
				getNewInstance(clazz);
				JOptionPane.showMessageDialog(HomePanel.this, "Done.");
			}
		}
	}
	
	private class StartButton extends JButton {
		public StartButton() {
			super("Start");
			addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					System.out.println("StartButton received mouseClicked event.");
					TreePath[] paths = tree.getSelectionPaths();
					boolean failed = true;
					if (paths != null && paths.length == 1) {
						Object object = paths[0].getLastPathComponent();
						if (object instanceof MyTree.LeafNode) {
							MyTree.LeafNode node = (MyTree.LeafNode) object;
							node.start();
							failed = false;
						}
					}
					if (failed) {
						JOptionPane.showMessageDialog(HomePanel.this, "Failed. Select one leaf from the tree.");
					}
				}
			});
		}
	}
}
